/****************************************************************************
 *  _____       ______  _____
 * |_   _|     |  ____|/ ____|
 *   | |  _ __ | |__  | (___    Institute of Embedded Systems
 *   | | | '_ \|  __|  \___ \   Zürcher Hochschule für Angewandte
 *  _| |_| | | | |____ ____) |  Wissenschaften
 * |_____|_| |_|______|_____/   8401 Winterthur, Switzerland
 *
 ****************************************************************************
 *
 * @version $Rev: 212 $
 * @author  $Author: bacr $
 * @date    $Date: 2014-01-10 14:09:50 +0100 (ven., 10 janv. 2014) $
 *
 ***************************************************************************/

#ifndef __PTP2_NODE_TABLE_H__
#define __PTP2_NODE_TABLE_H__

typedef struct ptp2_node_table_t           ptp2_node_table_t;

#include "hcpp_config.h"
#include "hcpp/ptp2_node_address.h"
#include "hcpp/ptp2_lut.h"
#include "hcpp/ptp2_slave.h"
#include "hcpp/ptp2_task.h"
#include "hcpp/ptp2_datasets.h"

struct ptp2_node_table_t {
    object_t                        obj;

    uint16_t                        size;                                               /**< actual size */
    ptp2_task_t                     lut_write_task;                                     /**< task to write the LUT table to the hardware */
    ptp2_task_t                     lease_durations_task;                               /**< task to check lease durations of signaling grants */

    uint16_t                        idx_table[PTP2_NODE_TABLE_MAX_ENTRIES];             /**< index table, sort by lut entry address (raw) */

    /* node address table*/
    ptp2_node_address_t             address_table[PTP2_NODE_TABLE_MAX_ENTRIES];          /**< array of node addresses, unsorted, shared index */

    /* lut */
    ptp2_lut_entry_t                lut_table[PTP2_NODE_TABLE_MAX_ENTRIES];             /**< array of lut entries, unsorted, shared index */
    bool                            lut_changed;                                        /**< has lut table changed? */

    uint16_t                        idx_remove_list[PTP2_NODE_TABLE_MAX_ENTRIES];       /**< array of indexes from index table, ready to remove */
    uint16_t                        idx_remove_size;                                    /**< size of indexes to remove */

    /* slave table */
    ptp2_slave_t                    slave_table[PTP2_NODE_TABLE_MAX_ENTRIES];           /**< array of slaves, unsorted, shared index */

    /* foreign master table */
    ptp2_foreign_master_ds_t        foreign_master_ds[PTP2_NODE_TABLE_MAX_ENTRIES];     /**< array of foreign master datasets, unsorted, shared index */
    ptp2_foreign_master_ds_t       *er_best;                                            /**< the best master clock for that port */
};

bool    ptp2_node_table_init                                (ptp2_node_table_t *this);
void                    ptp2_node_table_clear                               (ptp2_node_table_t *this);
static inline uint16_t  ptp2_node_table_get_size                            (ptp2_node_table_t *this);
static inline uint16_t  ptp2_node_table_get_lut_index_by_index              (ptp2_node_table_t *this, uint16_t idx);
bool                    ptp2_node_table_get_index_by_address                (ptp2_node_table_t *this, ptp2_node_address_t *addr, uint16_t *idx_found);
bool    ptp2_node_table_get_slave_by_address                (ptp2_node_table_t *this, ptp2_node_address_t *addr, ptp2_slave_t **slave_found);
static inline bool      ptp2_node_table_get_slave_by_index                  (ptp2_node_table_t *this, uint16_t idx, ptp2_slave_t **slave_found);
bool    ptp2_node_table_get_foreign_master_ds_by_address    (ptp2_node_table_t *this, ptp2_node_address_t *addr, ptp2_foreign_master_ds_t **fm_ds);

/**
 * Get size of node table
 *
 * @param   this                reference to node table
 * @return                      size of node table
 */
static inline uint16_t
ptp2_node_table_get_size(ptp2_node_table_t *this)
{
    return this->size;
}

/**
 * Get lut index by index
 */
static inline uint16_t
ptp2_node_table_get_lut_index_by_index(ptp2_node_table_t *this, uint16_t idx)
{
    return this->idx_table[idx];
}

/**
 * Get slave reference by index (doesn't clone a slave).
 * Check of array bounds!
 *
 * @param   this                reference to node table
 * @param   idx                 index to lookup
 * @param   slave_found         reference to a slave or NULL
 * @return                      true, when slave reference is found, false otherwise (boundry check)
 */
static inline bool
ptp2_node_table_get_slave_by_index(ptp2_node_table_t *this, uint16_t idx, ptp2_slave_t **slave_found)
{
    if (idx >= this->size) {
        (*slave_found) = NULL;
        return false;
    }

    (*slave_found) = &(this->slave_table[this->idx_table[idx]]);

    return true;
}

#endif

